package mammuthus.tool

import java.lang.management.ManagementFactory
import mammuthus.slave.ShellCommand
import mammuthus.protocal._
import java.io.{FileWriter, File}
import net.csdn.common.logging.Loggers
import mammuthus.template.DockerCommand
import mammuthus.protocal.DockerInstance
import mammuthus.protocal.AppInfo
import mammuthus.protocal.DiskInfo
import mammuthus.protocal.Docker
import org.apache.commons.io.FileUtils
import mammuthus.command.PidCommand

/**
 * 4/30/15 WilliamZhu(allwefantasy@gmail.com)
 */
class SystemTool

object SystemTool extends DockerCommand with PidCommand {
  val logger = Loggers.getLogger(classOf[SystemTool])

  def cpuCores = Runtime.getRuntime().availableProcessors()

  def memory = ManagementFactory.
    getOperatingSystemMXBean().
    asInstanceOf[com.sun.management.OperatingSystemMXBean].
    getTotalPhysicalMemorySize() / (1024 * 1024)

  def ip: Option[List[Eth]] = {
    import java.net._
    import scala.collection.JavaConversions._
    try {
      Some(NetworkInterface.getNetworkInterfaces().filter(f => f.isUp).
        map {
        f =>
          val kk = f.getInetAddresses.filter(f => f.getHostAddress.split("\\.").size == 4).toList
          val ipv4 = if (kk.length == 0) "-" else kk(0).getHostAddress
          val kk2 = f.getInetAddresses.filterNot(f => f.getHostAddress.split("\\.").size == 4).toList
          val ipv6 = if (kk2.length == 0) "-" else kk2(0).getHostAddress
          Eth(f.getName, ipv4, ipv6)
      }.toList)
    } catch {
      case e: Exception =>
        None
    }
  }

  def hostName: Option[String] = {
    import java.net._
    try {
      val localhost = InetAddress.getLocalHost
      Some(localhost.getHostName)
    } catch {
      case e: Exception =>
        None
    }
  }

  def disk = {
    val abc = ShellCommand.exec("df")
    abc.split("\n").filter(f => f.startsWith("/dev/")).map {
      f =>
        val a = f.split("\\s+")
        DiskInfo(a(0), a(5), a(1).toLong, a(2).toLong)
    }.toList
  }

  import net.liftweb.{json => SJSon}

  implicit val formats = SJSon.Serialization.formats(SJSon.NoTypeHints)

  def app = {
    val file = new File("/data/1/usr/local/appinfo")
    if (file.exists()) {
      file.listFiles().map {
        k =>
          try {
            val temp = SJSon.parse(FileUtils.readFileToString(k)).extract[Map[String, String]]

            val clientPort = temp.getOrElse("clientPort", "-1").toInt

            val pidInfo = try appPidsCollect(temp("appName"), temp("installPath")) catch {
              case e: Exception => logger.info("fetch pid fail", e)
                List()
            }

            AppInfo(temp("appName"), temp("version"), temp("installPath"), clientPort, temp, pidInfo)
          } catch {
            case e: Exception =>
              logger.info("parse app info error:", e)
              null
          }
      }.filter(_ != null).toList
    }
    else List[AppInfo]()
  }


  def docker: Docker = {
    val res = dockerVersion
    if (res._1 != 0) return Docker(false, List())
    val instances = dockerInstanceIds.map {
      f =>
        DockerInstance(f, dockerIp(f), DockerRegistry(isDockerRegistry(f)))
    }.filterNot(f => f.id.isEmpty).toList
    Docker(true, instances)
  }

  def writeJSONFile(path: String, msg: Map[String, String]): (Boolean, String) = {
    import net.liftweb.{json => SJSon}
    implicit val formats = SJSon.Serialization.formats(SJSon.NoTypeHints)
    val temp = new File(path)
    if (!temp.exists() || temp.isDirectory) return (false, s"$path is not exits or is directory. should be file")

    val info = SJSon.parse(FileUtils.readFileToString(new File(path))).extract[Map[String, String]]
    val info2 = info ++ msg
    FileUtils.write(new File(path), SJSon.Serialization.write(info2))

    return (true, "")
  }

  def writeFile(path: String, msg: String, append: Boolean): (Boolean, String) = {
    val fileWriter = new FileWriter(path, append)
    try {
      fileWriter.write(msg)
    } catch {
      case e: Exception =>
        val _msg = s"write file $path ($append) fail"
        logger.info(_msg, e)
        return (false, _msg)
    } finally {
      fileWriter.close()
    }
    return (true, "")
  }


}
